// this file manage the client socket

var clients = [];

var CHECK_INTERVAL = 50 * 1000; // check frequency unit:ms
var MAX_TICK_TIME = 2 * CHECK_INTERVAL; // unit:ms
var autoCheck;

// auto check, if the socket in array not tick too long, kick it as dead
function autoCheckValid() {
	// already has a timer check, do nothing
	if (autoCheck) {
		return;
	} 

	console.log('start timer for check timeout tick');
	autoCheck = setInterval(checkValid, CHECK_INTERVAL);
}

function checkValid() {
	if (clients.length === 0) {
		console.log('empty clients, dismiss timer');
		clearInterval(autoCheck);
		autoCheck = null;
		return;
	}

	// no timer check and size not zero, need start timer
	console.log('check now, length=' + clients.length + ', at ' + new Date().getTime());
	//	
	var invalidList = [];
	for (var i = 0; i < clients.length; i++) {
		var item = clients[i]
		var timeOut = new Date().getTime() - item.lastTick > MAX_TICK_TIME;
		if (timeOut) {
			console.log('find timeout:' + item.clientInfo);
			invalidList.push(item);
		}

		if (!item.socket || !item.socket.writable) {
			invalidList.push(item);
		}
	}

	// handle invalid
	if (invalidList.length) {
		console.log('to be end, size=' + invalidList.length);
	}
	invalidList.forEach(function(item) {
		item.socket.end();
	});
}

//
function getClientBySocket(socket) {
	if (!socket) {
		return null;
	}

	for (var i = 0; i < clients.length; i++) {
		var clientOne = clients[i];
		if (socket === clientOne.socket) {
			return clientOne;
		}
	}
	console.log('getClientBySocket -> socket not found');
}

function getClientByClientInfo(clientInfo) {
	if (!clientInfo) {
		return null;
	}

	for (var i = 0; i < clients.length; i++) {
		var clientOne = clients[i];
		if (clientInfo === clientOne.clientInfo) {
			return clientOne;
		}
	}
	console.log('getClientByClientInfo -> socket not found');
}

// add check
function add(clientOne) {
	// check if there is a same clientInfo in array
	var sameInfoObj;
	for (var i = 0; i < clients.length; i++) {
		var item = clients[i];
		if (item.clientInfo === clientOne.clientInfo) {
			sameInfoObj = item;
		}
	}

	if (sameInfoObj) { // end old, push new
		sameInfoObj.socket.end();
		clients.push(clientOne);
	} else {
		console.log('add new client');
		clients.push(clientOne);
	}
	autoCheckValid();
}

function listAll() {
	var allInfo = [];
	clients.forEach(function(item) {
		appInfo.push(item.clientInfo);
	});
}

function sendMsg(clientInfo, msg) {
	console.log('sendMsg'+ ', msg=' + msg+',clientInfo=' + clientInfo );
	var target = getClientByClientInfo(clientInfo);
	if (!target) {
		console.log('alive socket not found: clientInfo=' + clientInfo);
	} else {
		if (target.socket.writable) {
			target.socket.write(msg);
		} else {
			console.log('socket died, info =' + clientInfo);
			removeAndEnd(target);
		}
	}
}

// not call this method, call socket.end() instead
function remove(clientOne) {
	if (!clientOne) {
		console.log('remove, null arg');
		return;
	}

	// console.log('remove a closed socket');
	var index = clients.indexOf(clientOne);
	if (index >= 0) {
		console.log('remove from list:' + clientOne.clientInfo);
		clients.splice(index, 1);
	} else {
		console.log('already removed');
	}
}

function getAllOnline() {
	var listOfClientInfo = [];
	clients.forEach(function(item) {
		if (item.socket.writable) {
			listOfClientInfo.push(item.clientInfo);
		} else {
			removeAndEnd();
		}
	});
	return listOfClientInfo;
}

module.exports = {
	getClientBySocket: getClientBySocket,
	getClientByClientInfo: getClientByClientInfo,
	add: add,
	listAll: listAll,
	sendMsg: sendMsg,
	remove: remove,
	getAllOnline: getAllOnline
}